package com.jeeplus.test.jlnu.graduationInfo.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeeplus.sys.domain.Office;
import com.jeeplus.sys.service.OfficeService;
import com.jeeplus.test.jlnu.admissionInfo.domain.entity.ImportFailLog;
import com.jeeplus.test.jlnu.changeStuInfo.domain.entity.ChangeStuInfo;
import com.jeeplus.test.jlnu.graduationInfo.domain.entity.NewGraduationInfo;
import com.jeeplus.test.jlnu.graduationInfo.domain.vo.NewGraduationInfoReqVo;
import com.jeeplus.test.jlnu.graduationInfo.mapper.NewGraduationInfoMapper;
import com.jeeplus.test.jlnu.graduationInfo.service.NewGraduationInfoService;
import com.jeeplus.test.jlnu.graduationInfo.utils.GrayStyleHandlerGraduation;
import com.jeeplus.test.jlnu.timeConfigManage.service.TimeConfigService;
import com.jeeplus.test.tools.resp.R;
import com.jeeplus.test.tools.utils.MinioUtil;
import liquibase.util.file.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.beans.factory.annotation.Value;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class NewGraduationInfoServiceImpl implements NewGraduationInfoService {

    @Autowired
    NewGraduationInfoMapper graduationInfoMapper;

    @Autowired
    private OfficeService officeService;

    @Autowired
    private NewGraduationInfoService graduationInfoService;

    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private TimeConfigService timeConfigService;

    @Value("${config.accessory.minIO.bucketName}")
    private String bucketName;

    @Value("${config.accessory.minIO.endpoint}")
    private String minIoUrl;


    //分页查询
    @Override
    public Page<NewGraduationInfoReqVo> getGraduationInfoPage(NewGraduationInfoReqVo newGraduationInfoReqVo, Page<NewGraduationInfoReqVo> page) {

        String officeType = getOfficeWithCache(newGraduationInfoReqVo.getOfficeId(),new HashMap<>());
        // 1. 获取分页结果和字段配置信息
        newGraduationInfoReqVo.setOfficeType(officeType);
        if ("4".equals(officeType) || "6".equals(officeType)) {
            newGraduationInfoReqVo.setOfficeId(null); // 确保 COUNT 查询不触发 office_id 条件
        }
        if (StringUtils.isNotEmpty(newGraduationInfoReqVo.getTransferState())) {
            String[] arr = newGraduationInfoReqVo.getTransferState().split(",");
            List<String> list = Arrays.asList(arr);
            newGraduationInfoReqVo.setTransferStateList(list);
        }
        Page<NewGraduationInfoReqVo> graduationInfoPage = graduationInfoMapper.getGraduationInfoPage(newGraduationInfoReqVo, page);
        return graduationInfoPage;
    }

    //模板下载
    @Override
    public ResponseEntity<byte[]> graduationTemplate(List<String> ids) {

        List<NewGraduationInfo> graduationInfos = graduationInfoMapper.selectBatchIds(ids);
        // 生成 Excel 文件
        byte[] excelBytes = generateExcel(graduationInfos);

        // 返回 ResponseEntity 响应给前端
        HttpHeaders headers = new HttpHeaders();
        headers.setContentDispositionFormData("attachment", "admission_data.xlsx");
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        return new ResponseEntity<>(excelBytes, headers, HttpStatus.OK);
    }

    @Override
    public NewGraduationInfo selectByStudentId(String studentId) {
        return graduationInfoMapper.selectByStudentId(studentId);
    }

    @Override
    public void updateById(NewGraduationInfo existingRecord) {
        graduationInfoMapper.updateById(existingRecord);
    }

    @Override
    public void insert(NewGraduationInfo newRecord) {
        graduationInfoMapper.insert(newRecord);
    }

    @Override
    public int updateByIdBatch(List<String> studentIds, NewGraduationInfo graduationInfo) {
        return graduationInfoMapper.updateByIdBatch(studentIds,graduationInfo);
    }

    @Override
    public int approval(String submitType, List<String> ids) {
        return graduationInfoMapper.updateSubmitTypeByIds(submitType,ids);
    }

    @Override
    public Page<ImportFailLog> getImportDataPage(int pageNum, int pageSize, Date startTime, Date endTime, String fileName) {
        // 计算偏移量，注意 pageNum 从 1 开始，因此需要减去 1
        int offset = (pageNum - 1) * pageSize;

        // 查询当前页的数据
        List<ImportFailLog> data = graduationInfoMapper.selectPage(offset, pageSize,startTime,endTime,fileName);

        // 创建分页对象
        Page<ImportFailLog> page = new Page<>();
        page.setRecords(data);

        // 获取总记录数
        int totalCount = graduationInfoMapper.selectTotalCount(startTime,endTime);
        page.setTotal(totalCount);

        return page;
    }

    @Override
    public void insertImportLog(ImportFailLog failLog) {
        graduationInfoMapper.insertImportLog(failLog);
    }

    @Override
    public R importGraduationData(MultipartFile file) {
        // 1. 基础校验
        if (file == null || file.isEmpty()) {
            return R.error("FILE_EMPTY", "上传文件不能为空");
        }
        if (!FilenameUtils.getExtension(file.getOriginalFilename()).equalsIgnoreCase("xlsx")) {
            return R.error("FILE_FORMAT_ERROR", "仅支持XLSX格式文件");
        }
        List<NewGraduationInfo> tempList = new ArrayList<>(); // 存储所有数据
        List<Integer> failRecords = new ArrayList<>(); // 记录失败的行号
        List<NewGraduationInfo> newList = new ArrayList<>(); // 存储导入数据


        try {
            EasyExcel.read(file.getInputStream(), NewGraduationInfo.class, new AnalysisEventListener<NewGraduationInfo>() {
                @Override
                public void invoke(NewGraduationInfo data, AnalysisContext context) {

                    // 自动填充校长名
                    if (data.getPrincipal() == null || data.getPrincipal().isEmpty()) {
                        String principal = timeConfigService.getPrincipalByDate(data.getGraduateDate());
                        data.setPrincipal(principal);
                    }
                    tempList.add(data);
                }

                @Override
                public void onException(Exception exception, AnalysisContext context) {
                    int rowIndex = context.readRowHolder().getRowIndex() + 1;
                    failRecords.add(rowIndex);
                    context.readRowHolder().setCurrentRowAnalysisResult(true); // 跳过当前行
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    // 解析完毕，不需要额外处理
                }
            }).sheet().doRead();
        } catch (Exception e) {
            return R.error("9999", "文件解析失败: " + e.getMessage());
        }

        List<String> list = new ArrayList<>();
        // 处理数据
        for (NewGraduationInfo admissionInfo : tempList) {
            try {
                NewGraduationInfo existingRecord = graduationInfoService.selectByStudentId(admissionInfo.getStudentId());

                if(existingRecord != null && existingRecord.getSubmitType() != null && existingRecord.getSubmitType().equals("2")){
                    list.add("姓名：" + existingRecord.getName());
                    continue;
                }
                updateOrInsertRecord(admissionInfo,existingRecord);
                newList.add(admissionInfo);
            } catch (Exception e) {
                //admissionInfo.setRemark("导入失败: " + e.getMessage());
            }
        }

        // 生成导入记录 Excel
        String failFileUrl = null;
        String realFileName = "";

        if (!newList.isEmpty()) {
            Map<String,String> map = generateFailedRecordsExcel(newList);
            failFileUrl = map.get("fileUrl");
            realFileName = map.get("fileName");

            String baseUrl = failFileUrl;

            // 存入日志
            ImportFailLog failLog = new ImportFailLog();

            failLog.setCreateTime(new Date());
            failLog.setMessage("导入记录文件: " + realFileName);
            failLog.setFileName(realFileName);
            failLog.setFileUrl(baseUrl);
            graduationInfoService.insertImportLog(failLog);



            // 存入日志
//            String fileId = IdUtil.simpleUUID();
//            String uploadPath = "/file/graduationExcel" + "/" + failFileUrl + "/";
//
//            WebsiteFile websiteFile = new WebsiteFile();
//            websiteFile.setId(fileId);
//            websiteFile.setFileUrl(baseUrl);
//            websiteFile.setFileName(realFileName);
//            websiteFile.setBucketName(uploadPath);
//            websiteFile.setBucketId("/file");
//            websiteFile.setCreateTime(new Date());
//            websiteFileService.save(websiteFile);
        }


        return R.suc(list.size() > 0 ? "部分数据导入成功" + list + "毕业信息已提交禁止重复导入" : "全部导入成功");
    }

    @Override
    public int batchUpdateGraduation(NewGraduationInfoReqVo newGraduationInfoReqVo) {
        return graduationInfoMapper.batchUpdateGraduation(newGraduationInfoReqVo.getIds(),newGraduationInfoReqVo.getTransferState());
    }


    private String getOfficeWithCache(String officeId, Map<String, Office> cache) {
        return cache.computeIfAbsent(officeId, k -> officeService.getById(k)).getType();
    }


    private List<NewGraduationInfo> mergeData(List<ChangeStuInfo> changeStuInfos, List<NewGraduationInfo> graduationInfos) {
        // 构建 学号 -> 教学档案 的映射
        Map<String, NewGraduationInfo> archiveMap = graduationInfos.stream()
                .collect(Collectors.toMap(NewGraduationInfo::getStudentId, ta -> ta));

        // 遍历录取信息，合并教学档案数据
        List<NewGraduationInfo> result = new ArrayList<>();
        for (ChangeStuInfo admission : changeStuInfos) {
            NewGraduationInfo archive = archiveMap.get(admission.getStudentId());
            NewGraduationInfo exportData = new NewGraduationInfo();

            // 录取信息数据
            BeanUtils.copyProperties(admission, exportData);

            // 教学档案数据
            if (archive != null) {
                BeanUtils.copyProperties(archive, exportData);
            }
            result.add(exportData);
        }
        return result;
    }


    private byte[] generateExcel(List<NewGraduationInfo> exportDataList) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        System.out.println("=== 开始生成 Excel ===");

        // 定义需要锁定的字段（Excel 表头名称）
        List<String> lockedFields = Arrays.asList("考生号", "准考证号", "学号", "姓名", "性别", "出生日期", "民族", "身份证号", "专业代码", "专业名称", "学制", "学习形式", "层次", "提交状态", "入学日期");

        EasyExcel.write(outputStream, NewGraduationInfo.class)
                .excludeColumnFieldNames(Arrays.asList("id", "officeType", "officeId", "submitType", "fileStatus", "fileRemark", "impType", "studentIds"))
                .registerWriteHandler(new GrayStyleHandlerGraduation(lockedFields))
                .sheet("毕业信息")
                .doWrite(exportDataList);

        System.out.println("=== Excel 生成完成 ===");

        // 使用 POI 获取 Workbook 和 Sheet，然后启用保护
        Workbook workbook = null;
        try {
            workbook = WorkbookFactory.create(new ByteArrayInputStream(outputStream.toByteArray()));
            Sheet sheet = workbook.getSheetAt(0);  // 获取第一个 sheet

            // 启用保护
            sheet.protectSheet("password");  // 设置工作表保护密码

        } catch (Exception e) {
            e.printStackTrace();
        }

        // 将工作簿保存回 ByteArrayOutputStream
        ByteArrayOutputStream finalOutputStream = new ByteArrayOutputStream();
        try {
            workbook.write(finalOutputStream);  // 写入工作簿到流
        } catch (IOException e) {
            e.printStackTrace();
        }

        return finalOutputStream.toByteArray();
    }

    private void updateOrInsertRecord(NewGraduationInfo graduationInfo,NewGraduationInfo existingRecord) {
        try {
            // 如果记录存在，更新记录
            if (existingRecord != null) {
                updateRecord(existingRecord, graduationInfo, 0);
                graduationInfoService.updateById(existingRecord);
            } else {
                // 如果没有记录，插入新记录
                NewGraduationInfo newRecord = new NewGraduationInfo();
                updateRecord(newRecord, graduationInfo, 1);
                graduationInfoService.insert(newRecord);
            }
        } catch (Exception e) {
            throw new RuntimeException("学号: " + graduationInfo.getStudentId() + " 导入失败，错误: " + e.getMessage());
        }
    }


    private void updateRecord(NewGraduationInfo record, NewGraduationInfo graduationInfoReqVo, int type) {
        if(type == 1){
              record.setExamineeNum(graduationInfoReqVo.getExamineeNum());
              record.setAdmissionNum(graduationInfoReqVo.getAdmissionNum());
              record.setStudentId(graduationInfoReqVo.getStudentId());
              record.setName(graduationInfoReqVo.getName());
              record.setGender(graduationInfoReqVo.getGender());
              record.setBirthday(graduationInfoReqVo.getBirthday());
              record.setNation(graduationInfoReqVo.getNation());
              record.setIdCard(graduationInfoReqVo.getIdCard());
              record.setMajorCode(graduationInfoReqVo.getMajorCode());
              record.setMajorName(graduationInfoReqVo.getMajorName());
              record.setEducationalSystem(graduationInfoReqVo.getEducationalSystem());
              record.setLearningForms(graduationInfoReqVo.getLearningForms());
              record.setGradation(graduationInfoReqVo.getGradation());
              record.setEnrollmentDate(graduationInfoReqVo.getEnrollmentDate());
        }

        record.setAge(graduationInfoReqVo.getAge());
        record.setPoliticalOutlook(graduationInfoReqVo.getPoliticalOutlook());
        record.setCaseTitle(graduationInfoReqVo.getCaseTitle());
        record.setDocumentTitle(graduationInfoReqVo.getDocumentTitle());
        record.setStorageLocation(graduationInfoReqVo.getStorageLocation());
        record.setPageLocation(graduationInfoReqVo.getPageLocation());
        record.setPageNumber(graduationInfoReqVo.getPageNumber());
        record.setResponsiblePerson(graduationInfoReqVo.getResponsiblePerson());
        record.setDateTime(graduationInfoReqVo.getDateTime());
        record.setStandards(graduationInfoReqVo.getStandards());
        record.setQuantity(graduationInfoReqVo.getQuantity());
        record.setPageCount(graduationInfoReqVo.getPageCount());
        record.setArchiveUnit(graduationInfoReqVo.getArchiveUnit());
        record.setTransferor(graduationInfoReqVo.getTransferor());
        record.setReceiver(graduationInfoReqVo.getReceiver());
        record.setTransferTime(graduationInfoReqVo.getTransferTime());
        record.setGraduateDate(graduationInfoReqVo.getGraduateDate());
        record.setGraduateConclusion(graduationInfoReqVo.getGraduateConclusion());
        record.setCertificateNo(graduationInfoReqVo.getCertificateNo());
        record.setCertificateDate(graduationInfoReqVo.getCertificateDate());
        record.setDegreeLevel(graduationInfoReqVo.getDegreeLevel());
        record.setDegreeType(graduationInfoReqVo.getDegreeType());
        record.setMajors(graduationInfoReqVo.getMajors());
        record.setMentor(graduationInfoReqVo.getMentor());
        record.setThesisTitle(graduationInfoReqVo.getThesisTitle());
        record.setDegreeNo(graduationInfoReqVo.getDegreeNo());
        record.setDegreeDate(graduationInfoReqVo.getDegreeDate());
        record.setPrincipal(graduationInfoReqVo.getPrincipal());
        record.setCorrespondence(graduationInfoReqVo.getCorrespondence());
        record.setReference(graduationInfoReqVo.getReference());
        record.setInformationSource(graduationInfoReqVo.getInformationSource());
        record.setRemark(graduationInfoReqVo.getRemark());
        record.setSubmitType("1");
        record.setImpType("1");
    }


    private Map<String,String> generateFailedRecordsExcel(List<NewGraduationInfo> failedRecords) {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            // 1. 生成 Excel 到内存
            EasyExcel.write(outputStream, NewGraduationInfo.class)
                    .excelType(ExcelTypeEnum.XLSX)
                    .sheet("导入记录")
                    .doWrite(failedRecords);

            // 生成日期路径
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
            String datePath = dateFormat.format(new Date());

            // 3. 生成唯一文件名和对象路径
            String fileName = "file_records_" + System.currentTimeMillis() + ".xlsx";
            String objectKey = String.format("graduationExcelFile/%s/%s", datePath, fileName);

            // 4. 上传到 MinIO
            InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
            minioUtil.uploadFile(inputStream, bucketName, objectKey, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

            // 5. 生成预签名 URL（可选）
//            String fileUrl = minioClient.getPresignedObjectUrl(
//                    GetPresignedObjectUrlArgs.builder()
//                            .bucket(bucketName)
//                            .object(objectKey)
//                            .expiry(1, TimeUnit.DAYS)
//                            .method(Method.GET)
//                            .build()
//            );
            // 6. 返回元数据
            Map<String, String> map = new HashMap<>();
            map.put("fileName", fileName);
            map.put("fileUrl", "graduationExcelFile/" + datePath);
            map.put("objectKey", objectKey); // 可选：存储完整路径用于后续管理
            map.put("dateFormat", String.valueOf(dateFormat));

            return map;
        } catch (Exception e) {
            throw new RuntimeException("生成导入记录文件失败", e);
        }
    }

}
